package Aweto

import (
	"bytes"
	"encoding/binary"
	"github.com/pkg/errors"
	"math"
)

//字节切片合并函数
func BytesCombine(pBytes ...[]byte) []byte {
	return bytes.Join(pBytes, []byte(""))
}

//字节交换函数
func ByteSwap(buf []byte) (err error) {
	if len(buf)%2 != 0 {
		return errors.New("Data is not word")
	}
	for i := 0; i < len(buf); i += 2 {
		buf[i], buf[i+1] = buf[i+1], buf[i]
	}
	return nil
}

//字交换函数
func WordSwap(buf []byte) (err error) {
	if len(buf)%4 != 0 {
		return errors.New("Data is not dword")
	}
	for i := 0; i < len(buf); i += 4 {
		buf[i+2], buf[i+3], buf[i], buf[i+1] = buf[i], buf[i+1], buf[i+2], buf[3]
	}
	return nil
}

//值转字节数组
func ToBytes(i interface{}, BigEndian bool, Swap int, Len int) (data []byte, err error) {
	switch i.(type) {
	case bool:
		data = make([]byte, 1)
		if i.(bool) {
			data[0] = 1
		} else {
			data[0] = 0
		}
	case int16:
		data = make([]byte, 2)
		binary.BigEndian.PutUint16(data, uint16(i.(int16)))
	case uint16:
		data = make([]byte, 2)
		binary.BigEndian.PutUint16(data, i.(uint16))
	case int32:
		data = make([]byte, 4)
		binary.BigEndian.PutUint32(data, uint32(i.(int32)))
	case uint32:
		data = make([]byte, 4)
		binary.BigEndian.PutUint32(data, i.(uint32))
	case int64:
		data = make([]byte, 8)
		binary.BigEndian.PutUint64(data, uint64(i.(int64)))
	case uint64:
		data = make([]byte, 8)
		binary.BigEndian.PutUint64(data, i.(uint64))
	case float32:
		data = make([]byte, 4)
		bits := math.Float32bits(i.(float32))
		binary.BigEndian.PutUint32(data, bits)
	case float64:
		data = make([]byte, 8)
		bits := math.Float64bits(i.(float64))
		binary.BigEndian.PutUint64(data, bits)
	}
	err = swap(data, Swap)
	if !BigEndian {
		big2little(data)
	}
	j := Len - len(data)
	for k := 0; k < j; k++ {
		if BigEndian {
			data = BytesCombine([]byte{0}, data)
		} else {
			data = BytesCombine(data, []byte{0})
		}
	}
	return
}

//字节数组转值
func ToValue(buf []byte, Type string, BigEndian bool, Swap int) (data interface{}, err error) {
	Len := len(buf)
	if !BigEndian {
		big2little(buf)
	}
	err = swap(buf, Swap)
	switch Type {
	case "bool":
		if Len < 1 {
			return nil, errors.New("Bytes length is not enough for bool")
		}
		v := buf[Len-1:]
		if v[0] == 1 {
			data = true
		} else {
			data = false
		}
	case "int16":
		if Len < 2 {
			return nil, errors.New("Bytes length is not enough for int16")
		}
		v := buf[Len-2:]
		data = int16(binary.BigEndian.Uint16(v))
	case "uint16":
		if Len < 2 {
			return nil, errors.New("Bytes length is not enough for uint16")
		}
		v := buf[Len-2:]
		data = binary.BigEndian.Uint16(v)
	case "int32":
		if Len < 4 {
			return nil, errors.New("Bytes length is not enough for int32")
		}
		v := buf[Len-4:]
		data = int32(binary.BigEndian.Uint32(v))
	case "uint32":
		if Len < 4 {
			return nil, errors.New("Bytes length is not enough for uint32")
		}
		v := buf[Len-4:]
		data = binary.BigEndian.Uint32(v)
	case "int64":
		if Len < 8 {
			return nil, errors.New("Bytes length is not enough for int64")
		}
		v := buf[Len-8:]
		data = int64(binary.BigEndian.Uint64(v))
	case "uint64":
		if Len < 8 {
			return nil, errors.New("Bytes length is not enough for uint64")
		}
		v := buf[Len-8:]
		data = binary.BigEndian.Uint64(v)
	case "float32":
		if Len < 4 {
			return nil, errors.New("Bytes length is not enough for float32")
		}
		v := buf[Len-4:]
		bits := binary.BigEndian.Uint32(v)
		data = math.Float32frombits(bits)
	case "float64":
		if Len < 8 {
			return nil, errors.New("Bytes length is not enough for float64")
		}
		v := buf[Len-8:]
		bits := binary.BigEndian.Uint64(v)
		data = math.Float64frombits(bits)
	}
	return
}
func big2little(buf []byte) {
	Len := len(buf)
	for i := 0; i < Len/2; i++ {
		buf[i], buf[Len-1-i] = buf[Len-1-i], buf[i]
	}
}
func swap(buf []byte, Swap int) (err error) {
	switch Swap {
	case 1:
		err = ByteSwap(buf)
	case 2:
		err = WordSwap(buf)
	}
	return
}
